package com.h2.ref.server.web.user.account;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.h2.common.util.email.IEmailProvider;
import com.h2.ref.server.auth.token.IRandomTokenService;
import com.h2.ref.server.user.IUserService;
import com.h2.ref.server.user.model.User;
import com.h2.ref.server.web.ViewConstants;

@Controller
public class UserActivationController implements MessageSourceAware {
   
   protected static final Logger LOG =
         LoggerFactory.getLogger(UserActivationController.class);
   
   ////
   
   private IUserService _userService;
   
   private IRandomTokenService _tokenService;
   
   private IEmailProvider _emailProvider;
   
   private MessageSourceAccessor _messages =
      SpringSecurityMessageSource.getAccessor();
   
   private String _baseUrl;
   
   ////
   ////
   
   @RequestMapping(value = ViewConstants.ACCOUNT_EMAIL_ACTIVATE)
   public String receiveActivationEmail(
         @RequestParam String code,
         @RequestParam String email,
         BindingResult result) {
      if (LOG.isTraceEnabled()) {
         LOG.trace("Recieved code: " + code);
      }
      if (!StringUtils.hasText(code)) {
         if (LOG.isTraceEnabled()) {
            LOG.trace("Activating User with code: " + code);
         }
         
         if (getTokenService().isTokenValid(code)) {
            
            User user = getUserService().findByEmail(email);
            if(user == null) {
               result.reject("email", "user.not.found");
               return ViewConstants.ACCOUNT_EMAIL_ACTIVATE;
            }
            //set the user as enabled
            User updateUser = new User();
            updateUser.setId(user.getId());
            updateUser.setActive(true);
            getUserService().update(updateUser);
            return ViewConstants.ACCOUNT_EMAIL_ACTIVATE;
         }
      }
      result.reject("code", "code.invalid");
      return ViewConstants.ACCOUNT_EMAIL_ACTIVATE;
   }
   
   public boolean sendActivationEmail(User user) {
      return sendActivationEmail(user,
            "email.email.new.subject",
            "email.email.new.message");
   }
   
   public boolean sendActivationEmail(User user,
         String subjectKey,
         String messageKey) {
      
      Locale locale = LocaleContextHolder.getLocale();
      if (LOG.isTraceEnabled()) {
         LOG.trace("Sending new user email, userId: " + user.getId());
      }
      
      String message = getMessageSource().getMessage(messageKey,
            new String[] {
               user.getName(),
               generateActivationLink(user)},
               locale);
      String subject = getMessageSource().getMessage(subjectKey);
      
      return getEmailProvider().sendTo(
            subject,
            message,
            user.getUserDetails().getEmail());
   }
   
   protected String generateActivationLink(User user) {
      String token = getTokenService().generateToken(9, 10);
      return generateActivationLink(user.getUserDetails().getEmail(), token);
   }
   
   protected String generateActivationLink(String email, String token) {
      try {
         return getBaseUrl() + ViewConstants.ACCOUNT_EMAIL_ACTIVATE + ".html"
               + "?email=" + URLEncoder.encode(email, "UTF-8")
               + "&code=" + URLEncoder.encode(token, "UTF-8");
      } catch (UnsupportedEncodingException exp) {
         LOG.error(exp.getMessage());
         LOG.debug("Details: ", exp);
         return null;
      }
   }

   /**
    * @return the tokenService
    */
   public IRandomTokenService getTokenService() {
      return _tokenService;
   }

   /**
    * @param tokenService the tokenService to set
    */
   @Required
   public void setTokenService(IRandomTokenService tokenService) {
      _tokenService = tokenService;
   }

   /**
    * @return the emailProvider
    */
   public IEmailProvider getEmailProvider() {
      return _emailProvider;
   }

   /**
    * @param emailProvider the emailProvider to set
    */
   @Required
   public void setEmailProvider(IEmailProvider emailProvider) {
      _emailProvider = emailProvider;
   }
   
   public MessageSourceAccessor getMessageSource() {
      return _messages;
   }
   
   @Override
   public void setMessageSource(MessageSource messageSource) {
      _messages = new MessageSourceAccessor(messageSource);
   }

   /**
    * @return the userService
    */
   public IUserService getUserService() {
      return _userService;
   }

   /**
    * @param userService the userService to set
    */
   public void setUserService(IUserService userService) {
      _userService = userService;
   }

   /**
    * @return the baseUrl
    */
   public String getBaseUrl() {
      return _baseUrl;
   }

   /**
    * @param baseUrl the baseUrl to set
    */
   public void setBaseUrl(String baseUrl) {
      _baseUrl = baseUrl;
   }
}
